React-ning createPortal API-si bo'yicha to'liq qo'llanma. Unda portal yaratish usullari, hodisalarni boshqarish strategiyalari va moslashuvchan UI'lar qurish uchun ilg'or qo'llanilish holatlari yoritilgan.
React createPortal: Portal yaratish va hodisalarni boshqarishni o'zlashtirish
React yordamida zamonaviy veb-dasturlashda asosiy hujjat tuzilmasi bilan uzviy bog'langan foydalanuvchi interfeyslarini yaratish juda muhim. React-ning komponent modeli virtual DOM-ni boshqarishda juda yaxshi ishlasa-da, ba'zida elementlarni oddiy komponent ierarxiyasidan tashqarida render qilishimiz kerak bo'ladi. Aynan shu yerda createPortal yordamga keladi. Ushbu qo'llanmada createPortal chuqur o'rganiladi, uning maqsadi, qo'llanilishi va hodisalarni boshqarish hamda murakkab UI elementlarini yaratish uchun ilg'or usullar ko'rib chiqiladi. Biz xalqarolashtirish masalalari, maxsus imkoniyatlar bo'yicha eng yaxshi amaliyotlar va yo'l qo'ymaslik kerak bo'lgan keng tarqalgan xatolarni ko'rib chiqamiz.
React createPortal nima?
createPortal - bu React komponentining bola elementlarini ota komponent ierarxiyasidan tashqarida, DOM daraxtining boshqa qismiga render qilish imkonini beruvchi React API-sidir. Bu, ayniqsa, modal oynalar, maslahatlar, ochiladigan menyular va qoplamalar kabi elementlarni yaratishda foydalidir, chunki ularni hujjatning eng yuqori darajasida yoki ma'lum bir konteyner ichida joylashtirish kerak bo'ladi, ularni ishga tushiradigan komponent React komponentlar daraxtida qayerda joylashganidan qat'i nazar.
createPortal bo'lmasa, bunga erishish ko'pincha DOM-ni to'g'ridan-to'g'ri boshqarish yoki CSS-da mutlaq pozitsiyalash kabi murakkab yechimlarni talab qiladi, bu esa joylashuv kontekstlari, z-index ziddiyatlari va maxsus imkoniyatlar bilan bog'liq muammolarga olib kelishi mumkin.
Nima uchun createPortal-dan foydalanish kerak?
Quyida createPortal-ning sizning React arsenalingizdagi qimmatli vosita ekanligining asosiy sabablari keltirilgan:
- Yaxshilangan DOM tuzilmasi: Komponentlarni DOM ichida chuqur joylashtirishdan saqlaydi, bu esa toza va boshqarilishi oson tuzilmaga olib keladi. Bu, ayniqsa, ko'plab interaktiv elementlarga ega murakkab ilovalar uchun muhim.
- Soddalashtirilgan uslublar: Elementlarni murakkab CSS hiylalariga tayanmasdan, ko'rish oynasi (viewport) yoki ma'lum konteynerlarga nisbatan osongina joylashtirish imkonini beradi. Bu uslub va joylashuvni soddalashtiradi, ayniqsa boshqa kontentni qoplashi kerak bo'lgan elementlar bilan ishlaganda.
- Kengaytirilgan maxsus imkoniyatlar: Fokus va klaviatura navigatsiyasini komponent ierarxiyasidan mustaqil ravishda boshqarishga imkon berib, maxsus imkoniyatlarga ega UI-larni yaratishni osonlashtiradi. Masalan, fokusning modal oyna ichida qolishini ta'minlash.
- Yaxshiroq hodisalarni boshqarish: Hodisalarning portal kontentidan React daraxtiga to'g'ri tarqalishiga imkon beradi, bu esa ota komponentlarga biriktirilgan hodisa tinglovchilarining kutilganidek ishlashini ta'minlaydi.
createPortal-dan asosiy foydalanish
createPortal API ikkita argument qabul qiladi:
- Siz render qilmoqchi bo'lgan React tuguni (JSX).
- Tugunni render qilmoqchi bo'lgan DOM elementi. Ushbu DOM elementi
createPortal-dan foydalanadigan komponent yuklanishidan oldin mavjud bo'lishi kerak.
Mana oddiy misol:
Misol: Modal oynani render qilish
Aytaylik, sizda body elementining oxirida render qilmoqchi bo'lgan modal komponentingiz bor.
import React from 'react';
import ReactDOM from 'react-dom';
function Modal({ children, isOpen, onClose }) {
if (!isOpen) return null;
const modalRoot = document.getElementById('modal-root'); // HTML faylingizda <div id="modal-root"></div> bor deb taxmin qilinadi
if (!modalRoot) {
console.error('Modal root elementi topilmadi!');
return null;
}
return ReactDOM.createPortal(
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
{children}
</div>
</div>,
modalRoot
);
}
export default Modal;
Tushuntirish:
- Biz
ReactDOM-ni import qilamiz, chunkicreatePortalbuReactDOMobyektining metodi. - HTML-da
modal-rootID-siga ega DOM elementi mavjud deb taxmin qilamiz. Modal aynan shu yerda render qilinadi. Ushbu element mavjudligiga ishonch hosil qiling. Keng tarqalgan amaliyot -index.htmlfaylingizdagi yopiluvchi</body>tegidan oldin<div id="modal-root"></div>qo'shish. - Biz modalning JSX-ni
modalRootelementiga render qilish uchunReactDOM.createPortal-dan foydalanamiz. - Biz
e.stopPropagation()-dan foydalanib, modal kontentidagionClickhodisasining qoplamadagionCloseishlovchisini ishga tushirishini oldini olamiz. Bu modal ichiga bosilganda uning yopilmasligini ta'minlaydi.
Qo'llanilishi:
import React, { useState } from 'react';
import Modal from './Modal';
function App() {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<div>
<button onClick={() => setIsModalOpen(true)}>Modalni ochish</button>
<Modal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)}>
<h2>Modal kontenti</h2>
<p>Bu modalning kontenti.</p>
<button onClick={() => setIsModalOpen(false)}>Yopish</button>
</Modal>
</div>
);
}
export default App;
Ushbu misol modalni oddiy komponent ierarxiyasidan tashqarida qanday render qilishni ko'rsatadi, bu sizga uni sahifada mutlaq joylashtirish imkonini beradi. createPortal-dan bu tarzda foydalanish joylashuv kontekstlari bilan bog'liq keng tarqalgan muammolarni hal qiladi va ilovangiz bo'ylab bir xil modal uslublarini osongina yaratishga imkon beradi.
createPortal bilan hodisalarni boshqarish
createPortal-ning asosiy afzalliklaridan biri shundaki, u React-ning oddiy hodisalarning yuqoriga ko'tarilish (event bubbling) xususiyatini saqlab qoladi. Bu shuni anglatadiki, portal kontenti ichida paydo bo'lgan hodisalar hali ham React komponentlar daraxti bo'ylab yuqoriga tarqaladi va ota komponentlarga ularni boshqarish imkonini beradi.
Biroq, hodisalar portal chegarasini kesib o'tganda qanday boshqarilishini tushunish muhimdir.
Misol: Portal tashqarisidagi hodisalarni boshqarish
import React, { useState, useRef, useEffect } from 'react';
import ReactDOM from 'react-dom';
function OutsideClickExample() {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef(null);
const portalRoot = document.getElementById('portal-root');
useEffect(() => {
function handleClickOutside(event) {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
setIsOpen(false);
}
}
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [dropdownRef]);
return (
<div>
<button onClick={() => setIsOpen(!isOpen)}>Ochiladigan menyuni almashtirish</button>
{isOpen && portalRoot && ReactDOM.createPortal(
<div ref={dropdownRef} style={{ position: 'absolute', top: '50px', left: '0', border: '1px solid black', padding: '10px', backgroundColor: 'white' }}>
Ochiladigan menyu kontenti
</div>,
portalRoot
)}
</div>
);
}
export default OutsideClickExample;
Tushuntirish:
- Portal ichida render qilingan ochiladigan menyu elementiga kirish uchun
ref-dan foydalanamiz. - Ochiladigan menyudan tashqaridagi bosishlarni aniqlash uchun
document-gamousedownhodisa tinglovchisini biriktiramiz. - Hodisa tinglovchisi ichida, bosishning ochiladigan menyu tashqarisida sodir bo'lganligini
dropdownRef.current.contains(event.target)yordamida tekshiramiz. - Agar bosish ochiladigan menyudan tashqarida sodir bo'lsa,
isOpen-nifalse-ga o'rnatib, uni yopamiz.
Ushbu misol portal kontentidan tashqarida sodir bo'ladigan hodisalarni qanday boshqarishni ko'rsatadi, bu sizga atrofdagi hujjatdagi foydalanuvchi harakatlariga javob beradigan interaktiv elementlarni yaratish imkonini beradi.
Ilg'or qo'llanilish holatlari
createPortal faqat oddiy modallar va maslahatlar bilan cheklanmaydi. Uni turli ilg'or stsenariylarda ishlatish mumkin, jumladan:
- Kontekst menyulari: Sichqonchaning o'ng tugmasi bosilganda kursor yaqinida kontekst menyularini dinamik ravishda render qilish.
- Bildirishnomalar: Komponent ierarxiyasidan qat'i nazar, ekraning yuqori qismida bildirishnomalarni ko'rsatish.
- Maxsus qalqib chiquvchi oynalar: Ilg'or joylashuv va uslublarga ega maxsus qalqib chiquvchi komponentlarni yaratish.
- Uchinchi tomon kutubxonalari bilan integratsiya: React komponentlarini ma'lum DOM tuzilmalarini talab qiladigan uchinchi tomon kutubxonalari bilan integratsiya qilish uchun
createPortal-dan foydalanish.
Misol: Kontekst menyusini yaratish
import React, { useState, useRef, useEffect } from 'react';
import ReactDOM from 'react-dom';
function ContextMenuExample() {
const [contextMenu, setContextMenu] = useState(null);
const menuRef = useRef(null);
useEffect(() => {
function handleClickOutside(event) {
if (menuRef.current && !menuRef.current.contains(event.target)) {
setContextMenu(null);
}
}
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [menuRef]);
const handleContextMenu = (event) => {
event.preventDefault();
setContextMenu({
x: event.clientX,
y: event.clientY,
});
};
const portalRoot = document.getElementById('portal-root');
return (
<div onContextMenu={handleContextMenu} style={{ border: '1px solid black', padding: '20px' }}>
Kontekst menyusini ochish uchun shu yerga o'ng tugmani bosing
{contextMenu && portalRoot && ReactDOM.createPortal(
<div
ref={menuRef}
style={{
position: 'absolute',
top: contextMenu.y,
left: contextMenu.x,
border: '1px solid black',
padding: '10px',
backgroundColor: 'white',
}}
>
<ul>
<li>Variant 1</li>
<li>Variant 2</li>
<li>Variant 3</li>
</ul>
</div>,
portalRoot
)}
</div>
);
}
export default ContextMenuExample;
Tushuntirish:
- Nishondagi elementga o'ng tugma bosilishini aniqlash uchun
onContextMenuhodisasidan foydalanamiz. event.preventDefault()yordamida standart kontekst menyusining paydo bo'lishini oldini olamiz.- Sichqoncha koordinatalarini
contextMenuholat o'zgaruvchisida saqlaymiz. - Kontekst menyusini sichqoncha koordinatalarida joylashtirilgan portal ichida render qilamiz.
- Foydalanuvchi menyudan tashqarida bosganda uni yopish uchun oldingi misoldagi kabi tashqaridagi bosishni aniqlash mantig'ini qo'shamiz.
Maxsus imkoniyatlar bo'yicha mulohazalar
createPortal-dan foydalanganda, ilovangiz barcha uchun foydalanishga yaroqli bo'lishini ta'minlash uchun maxsus imkoniyatlarni hisobga olish juda muhim.
Fokusni boshqarish
Portal ochilganda (masalan, modal), fokus avtomatik ravishda portal ichidagi birinchi interaktiv elementga o'tkazilishini ta'minlashingiz kerak. Bu klaviatura yoki ekran o'quvchi bilan harakatlanadigan foydalanuvchilarga portal kontentiga osongina kirishga yordam beradi.
Portal yopilganda, fokusni portalni ochishga sabab bo'lgan elementga qaytarishingiz kerak. Bu izchil navigatsiya oqimini saqlaydi.
ARIA atributlari
Portal kontenti haqida semantik ma'lumot berish uchun ARIA atributlaridan foydalaning. Masalan, modal dialog ekanligini bildirish uchun modal elementida aria-modal="true"-dan foydalaning. Modalni uning sarlavhasi bilan bog'lash uchun aria-labelledby va uning tavsifi bilan bog'lash uchun aria-describedby-dan foydalaning.
Klaviatura navigatsiyasi
Foydalanuvchilar portal kontentini klaviatura yordamida boshqara olishiga ishonch hosil qiling. Fokus tartibini boshqarish uchun tabindex atributidan foydalaning va barcha interaktiv elementlarga klaviatura orqali yetib borish mumkinligini ta'minlang.
Foydalanuvchilar tasodifan undan tashqariga chiqa olmasligi uchun fokusni portal ichida ushlab turishni o'ylab ko'ring. Bunga Tab tugmachasini tinglash va fokusni dasturiy ravishda portal ichidagi birinchi yoki oxirgi interaktiv elementga o'tkazish orqali erishish mumkin.
Misol: Maxsus imkoniyatlarga ega modal
import React, { useState, useRef, useEffect } from 'react';
import ReactDOM from 'react-dom';
function AccessibleModal({ children, isOpen, onClose, labelledBy, describedBy }) {
const modalRef = useRef(null);
const firstFocusableElementRef = useRef(null);
const [previouslyFocusedElement, setPreviouslyFocusedElement] = useState(null);
const modalRoot = document.getElementById('modal-root');
useEffect(() => {
if (isOpen) {
// Modal ochilishidan oldin joriy fokusdagi elementni saqlab qo'yish.
setPreviouslyFocusedElement(document.activeElement);
// Modaldagi birinchi fokuslanadigan elementga fokusni o'tkazish.
if (firstFocusableElementRef.current) {
firstFocusableElementRef.current.focus();
}
// Fokusni modal ichida ushlab turish.
function handleKeyDown(event) {
if (event.key === 'Tab') {
const focusableElements = modalRef.current.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstFocusableElement = focusableElements[0];
const lastFocusableElement = focusableElements[focusableElements.length - 1];
if (event.shiftKey) {
// Shift + Tab
if (document.activeElement === firstFocusableElement) {
lastFocusableElement.focus();
event.preventDefault();
}
} else {
// Tab
if (document.activeElement === lastFocusableElement) {
firstFocusableElement.focus();
event.preventDefault();
}
}
}
}
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
// Modal ochilishidan oldin fokusda bo'lgan elementga fokusni qaytarish.
if(previouslyFocusedElement && previouslyFocusedElement.focus) {
previouslyFocusedElement.focus();
}
};
}
}, [isOpen, previouslyFocusedElement]);
if (!isOpen) return null;
return ReactDOM.createPortal(
<div
className="modal-overlay"
onClick={onClose}
aria-modal="true"
aria-labelledby={labelledBy}
aria-describedby={describedBy}
ref={modalRef}
>
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
<h2 id={labelledBy}>Modal sarlavhasi</h2>
<p id={describedBy}>Bu modalning kontenti.</p>
<button ref={firstFocusableElementRef} onClick={onClose}>
Yopish
</button>
{children}
</div>
</div>,
modalRoot
);
}
export default AccessibleModal;
Tushuntirish:
- Modal haqida semantik ma'lumot berish uchun
aria-modal,aria-labelledbyvaaria-describedbykabi ARIA atributlaridan foydalanamiz. - Modal ochilganda va yopilganda fokusni boshqarish uchun
useEffecthook-idan foydalanamiz. - Modal ochilishidan oldin joriy fokusdagi elementni saqlaymiz va modal yopilganda fokusni unga qaytaramiz.
keydownhodisa tinglovchisi yordamida fokusni modal ichida ushlab turamiz.
Xalqarolashtirish (i18n) bo'yicha mulohazalar
Global auditoriya uchun ilovalar ishlab chiqishda xalqarolashtirish (i18n) muhim ahamiyatga ega. createPortal-dan foydalanganda bir nechta jihatlarni yodda tutish kerak:
- Matn yo'nalishi (RTL/LTR): Uslublaringiz chapdan o'ngga (LTR) va o'ngdan chapga (RTL) yoziladigan tillarni qo'llab-quvvatlashiga ishonch hosil qiling. Bu CSS-da mantiqiy xususiyatlardan (masalan,
margin-lefto'rnigamargin-inline-start) foydalanishni va HTML elementidadiratributini to'g'ri o'rnatishni o'z ichiga olishi mumkin. - Kontentni mahalliylashtirish: Portal ichidagi barcha matnlar foydalanuvchining afzal ko'rgan tiliga mahalliylashtirilishi kerak. Tarjimalarni boshqarish uchun i18n kutubxonasidan (masalan,
react-intl,i18next) foydalaning. - Raqam va sana formatlash: Raqamlar va sanalarni foydalanuvchining hududiy sozlamalariga muvofiq formatlang.
IntlAPI buning uchun funksiyalarni taqdim etadi. - Madaniy an'analar: UI elementlari bilan bog'liq madaniy an'analardan xabardor bo'ling. Masalan, tugmalarning joylashuvi turli madaniyatlarda farq qilishi mumkin.
Misol: react-intl bilan i18n
import React from 'react';
import { FormattedMessage } from 'react-intl';
function MyComponent() {
return (
<div>
<FormattedMessage id="myComponent.greeting" defaultMessage="Salom, dunyo!" />
</div>
);
}
export default MyComponent;
react-intl-dan FormattedMessage komponenti foydalanuvchining hududiy sozlamalariga asoslanib tarjima qilingan xabarni oladi. react-intl-ni turli tillar uchun tarjimalaringiz bilan sozlang.
Keng tarqalgan xatolar va ularning yechimlari
createPortal kuchli vosita bo'lsa-da, ba'zi keng tarqalgan xatolardan va ularni qanday oldini olishdan xabardor bo'lish muhim:
- Portal ildiz elementining yo'qligi: Portal ildizi sifatida ishlatadigan DOM elementingiz
createPortal-dan foydalanadigan komponent yuklanishidan oldin mavjudligiga ishonch hosil qiling. Yaxshi amaliyot - uni to'g'ridan-to'g'riindex.html-ga joylashtirish. - Z-Index ziddiyatlari:
createPortalbilan elementlarni joylashtirishda z-index qiymatlariga e'tibor bering. Joylashuv kontekstlarini boshqarish va portal kontentingiz to'g'ri ko'rsatilishini ta'minlash uchun CSS-dan foydalaning. - Hodisalarni boshqarish muammolari: Hodisalar portal orqali qanday tarqalishini tushuning va ularni to'g'ri boshqaring. Hodisalarning kutilmagan harakatlarni keltirib chiqarishini oldini olish uchun
e.stopPropagation()-dan foydalaning. - Xotira sizib chiqishi (Memory Leaks): Xotira sizib chiqishining oldini olish uchun
createPortal-dan foydalanadigan komponent demontaj qilinganda hodisa tinglovchilari va havolalarni to'g'ri tozalang. Bunga erishish uchun tozalash funksiyasiga egauseEffecthook-idan foydalaning. - Kutilmagan aylantirish (skrolling) muammolari: Portallar ba'zida sahifaning kutilgan aylantirish xatti-harakatlariga xalaqit berishi mumkin. Uslublaringiz aylantirishni to'sib qo'ymayotganiga va modal elementlar ochilganda va yopilganda sahifada sakrashlar yoki kutilmagan aylantirish harakatlariga sabab bo'lmasligiga ishonch hosil qiling.
Xulosa
React.createPortal React-da moslashuvchan, maxsus imkoniyatlarga ega va qo'llab-quvvatlanishi oson UI-larni yaratish uchun qimmatli vositadir. Uning maqsadini, qo'llanilishini va hodisalarni boshqarish hamda maxsus imkoniyatlar bo'yicha ilg'or usullarni tushunib, siz global auditoriya uchun yuqori darajadagi foydalanuvchi tajribasini ta'minlaydigan murakkab va jozibali veb-ilovalarni yaratish uchun uning kuchidan foydalanishingiz mumkin. Ilovalaringiz inklyuziv va barcha uchun foydalanishga yaroqli bo'lishini ta'minlash uchun xalqarolashtirish va maxsus imkoniyatlar bo'yicha eng yaxshi amaliyotlarni hisobga olishni unutmang.
Ushbu qo'llanmadagi ko'rsatmalar va misollarga amal qilib, siz keng tarqalgan UI muammolarini hal qilish va ajoyib veb-tajribalar yaratish uchun createPortal-dan ishonch bilan foydalanishingiz mumkin.